﻿using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using System.Collections;
using System.Collections.Generic;
using RAP.Framework.Libary.Utils;
using RAP.Framework.Libary.DomTemplateBuilder.Element;
using RAP.Framework.Libary.DomTemplateBuilder.ContentRender;
using RAP.Framework.Libary.DomTemplateBuilder.Handler;
using RAP.Framework.Libary.Utils.Collections.Dictionary;
using RAP.Framework.Libary.DomTemplateBuilder.Interface;

namespace RAP.Framework.Libary.DomTemplateBuilder.Configuration
{
  /// <summary>
  /// 配置节点对象（Template）
  /// </summary>
  public class TemplateItem : Hashtable, IElement, IDisposable
  {
    public TemplateItem()
    {
      this.ChildNodes = new List<ElementBase>();
      this.Attributes = new AttributeCollection();
      this.ChildTemplates = new ListDictionary<string, TemplateItem>();
      this.Enable = true;
    }

    #region 静态函数
    /// <summary>
    /// 检测访问者模板是否能访问被访问的模板
    /// </summary>
    /// <param name="accessor"></param>
    /// <param name="beAccessor"></param>
    /// <returns></returns>
    public static bool CheckTemplateAccessable(TemplateItem accessor, TemplateItem beAccessed)
    {
      if (accessor == null || beAccessed == null) return false;
      switch (beAccessed.AccessType)
      {
        case TemplateAccessTypes.Public:
          return true;

        case TemplateAccessTypes.Internal:
          return accessor.DomTemplate.NameSpace == beAccessed.DomTemplate.NameSpace;

        case TemplateAccessTypes.Private:
          return accessor.OwnerFile.FullName == beAccessed.OwnerFile.FullName;

        case TemplateAccessTypes.Closure:
          return accessor.FullName == beAccessed.ParentTemplate.FullName;

        default:
          return false;
      }
    }

    /// <summary>
    /// 检测指定完全名称的访问者模板是否能访问指定完全名称的模板
    /// </summary>
    /// <param name="accessor"></param>
    /// <param name="beAccessor"></param>
    /// <returns></returns>
    public static bool CheckTemplateAccessable(string accessor, string beAccessor)
    {
      return CheckTemplateAccessable(DomTemplateManager.Instance.GetTemplateItem(accessor), DomTemplateManager.Instance.GetTemplateItem(beAccessor));
    }

    /// <summary>
    /// 检测指定访问者模板是否能访问指定完全名称的模板
    /// </summary>
    /// <param name="accessor"></param>
    /// <param name="beAccessor"></param>
    /// <returns></returns>
    public static bool CheckTemplateAccessable(TemplateItem accessor, string beAccessor)
    {
      return CheckTemplateAccessable(accessor, DomTemplateManager.Instance.GetTemplateItem(beAccessor));
    }

    /// <summary>
    /// 根据XML节点创建配置节点
    /// </summary>
    /// <param name="node"></param>
    internal static void Create(XmlNode section, TemplateItem tpl, DomTemplate domTemplate)
    {
      tpl.DomTemplate = domTemplate;
      tpl.ConfigNode = section;
      section.Attributes.ToDictionary(tpl);
      Create(section, tpl, tpl);
    }

    /// <summary>
    /// 根据XML节点创建配置节点
    /// </summary>
    /// <param name="section"></param>
    /// <param name="parent"></param>
    internal static void Create(XmlNode section, TemplateItem tpl, IElement parent)
    {
      foreach (XmlNode node in section.ChildNodes)
      {
        switch (node.NodeType)
        {
          case XmlNodeType.Element:
            switch (node.Name)
            {
              case "Attributes":
                CreateAttributes(node, tpl);
                break;

              case "Template":
                CreateChildTemplate(node, tpl);
                break;

              case "Templates":
                Create(node, tpl, tpl);
                break;

              default:
                CreateElement(node, tpl, parent);
                break;
            }
            break;

          case XmlNodeType.Text:
          case XmlNodeType.CDATA:
            CreateTextElement(node, tpl, parent);
            break;
        }
      }
    }

    /// <summary>
    /// 创建子模板
    /// </summary>
    /// <param name="section"></param>
    /// <param name="parent"></param>
    internal static void CreateChildTemplate(XmlNode section, TemplateItem parent)
    {
      if (section.NodeType != XmlNodeType.Element)
      {
        return;
      }
      var childTemplate = new TemplateItem() { ParentTemplate = parent };
      Create(section, childTemplate, parent.DomTemplate);
      childTemplate.AccessType = TemplateAccessTypes.Closure;
      parent.ChildTemplates.Add(childTemplate.Name, childTemplate);
    }

    /// <summary>
    /// 创建自定义属性集合
    /// </summary>
    /// <param name="nodeAttrs"></param>
    protected static void CreateAttributes(XmlNode nodeAttrs, TemplateItem tpl)
    {
      foreach (XmlNode node in nodeAttrs.ChildNodes)
      {
        if (node.NodeType == XmlNodeType.Element && node.Name == "Attribute")
        {
          var attrType = node.Attributes.ToString("Type", CustomerAttributeValueTypes.String);
          var attrName = node.Attributes.ToString("Name");
          object attrVal = null;
          switch (attrType)
          {
            case CustomerAttributeValueTypes.String:
              attrVal = node.InnerText.Trim();
              break;

            case CustomerAttributeValueTypes.Object:
              attrVal = node.InnerText?.Trim().Eval();
              break;
          }
          tpl.Attributes[attrName] = attrVal;
        }
      }
    }

    /// <summary>
    /// 创建一般元素
    /// </summary>
    /// <param name="node"></param>
    protected static ElementBase CreateElement(XmlNode node, TemplateItem tpl, IElement parent)
    {
      return CreateElement(node.Name, node, tpl, parent);
    }

    /// <summary>
    /// 根据节点TagName名称创建Element对象
    /// </summary>
    /// <param name="tagName"></param>
    /// <param name="node"></param>
    /// <param name="parentCollection"></param>
    protected static ElementBase CreateElement(string tagName, XmlNode node, TemplateItem tpl, IElement parent)
    {
      var elementType = tpl.DomTemplate.GetElementType(tagName);
      if (elementType == null)
      {
        throw new NullReferenceException(string.Format("Error!The tag name '{0}' is invalid.", tagName));
      }
      var ele = elementType.Assembly.CreateInstance(elementType.FullName) as ElementBase;
      ele.Template = tpl;
      ele.HandlerName = tagName;
      ele.Parent = parent as IElement;
      ele.Initialize(node);
      Create(node, tpl, ele);//递归创建子节点
      return ele;
    }

    /// <summary>
    /// 创建文本节点
    /// </summary>
    /// <param name="textNode"></param>
    protected static ElementBase CreateTextElement(XmlNode textNode, TemplateItem tpl, IElement parent)
    {
      var ele = CreateElement("SimpleText", textNode, tpl, parent) as SimpleText;
      ele.Content = textNode.Value;
      return ele;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="tpl"></param>
    /// <param name="rootParamObject"></param>
    /// <param name="parentParamObject"></param>
    /// <param name="context"></param>
    /// <returns></returns>
    internal static string DoRender(TemplateItem tpl, object rootParamObject, object parentParamObject, ITemplateRenderContext context)
    {
      if (!tpl.Enable)
      {
        return string.Empty;//如果当前模板被设置为无效，则直接返回空字符串
      }
      var result = new StringBuilder();
      context = context.IsNullValue(() =>
     {
       return new TemplateRenderContext();
     });
      context.EndTemplate = false;
      var curAttrs = context.CurrentAttributes;
      context.CurrentAttributes = tpl.Attributes;
      var callbacks = context.Callbacks;
      foreach (var ele in tpl.ChildNodes)
      {
        ele.Handler.DoRender(result, rootParamObject, parentParamObject, context);
        if (context.EndTemplate)
        {
          break;
        }
      }
      if (tpl.AccessType == TemplateAccessTypes.Public)
      {
        context.DoCallbacks = (data) =>
        {
          if (callbacks.IsNotNullOrEmpty())
          {
            context.CallbackResult = data;
            foreach (Action<object, ITemplateRenderContext> action in callbacks)
            {
              action(rootParamObject, context);
            }
            callbacks.Clear();
          }
          if (context != null)
          {
            context.Remove(Consts.TEMPLATE_CALLBACK);
            callbacks = null;
          }
        };
      }
      context.EndTemplate = false;
      context.CurrentAttributes = curAttrs;
      return result.ToString();
    }

    /// <summary>
    /// 逐级向上查找指定名称的子模板（先查找自己所属子模板，如果不存在，则查找父级模板的子模板，直到在全局模板中查找）
    /// </summary>
    /// <param name="tpl"></param>
    /// <param name="childTpl"></param>
    /// <returns></returns>
    internal static TemplateItem FindTemplate(TemplateItem tpl, string childTpl)
    {
      if (childTpl == tpl.FullName)
      {
        return tpl;
      }
      if (tpl.ChildTemplates.ContainsKey(childTpl))
      {
        return tpl.ChildTemplates[childTpl];
      }
      if (tpl.ParentTemplate != null)
      {
        return FindTemplate(tpl.ParentTemplate, childTpl);
      }
      return null;
    }
    #endregion

    #region 属性

    public IElement Parent { get; set; }

    public IHandler Handler { get; }

    /// <summary>
    /// 获取或设置该模板的父模板对象
    /// </summary>
    public TemplateItem ParentTemplate { get; set; }

    /// <summary>
    /// 子模板对象集合
    /// </summary>
    public IDictionary<string, TemplateItem> ChildTemplates { get; set; }

    /// <summary>
    /// 自定义属性集合
    /// </summary>
    public AttributeCollection Attributes { get; private set; }

    /// <summary>
    /// Template包含的子节点
    /// </summary>
    public IList<ElementBase> ChildNodes { get; set; }

    /// <summary>
    /// 
    /// </summary>
    public DomTemplate DomTemplate { get; set; }


    /// <summary>
    /// 当前TemplateItem对象对应的配置节点
    /// </summary>
    public XmlNode ConfigNode { get; set; }

    /// <summary>
    /// 当前模板是否有效
    /// </summary>
    public bool Enable { get; set; }

    private FileInfo _fileInfo = null;
    /// <summary>
    /// 配置所属文件对象
    /// </summary>
    public FileInfo OwnerFile
    {
      get
      {
        if (_fileInfo == null)
        {
          _fileInfo = new FileInfo(this.ConfigNode.OwnerDocument.BaseURI.Replace("file:///", ""));
        }
        return _fileInfo;
      }
    }

    /// <summary>
    /// 
    /// </summary>
    public string Name
    {
      get
      {
        return this.ToString("Name");
      }
      set
      {
        if (value.IsNullOrEmpty())
        {
          throw new NullReferenceException("Error!Template's attribute 'Name' is not allowed null or empty string.");
        }
        this["Name"] = value;
        _fullName = null;
      }
    }

    protected TemplateAccessTypes _accessType = TemplateAccessTypes.Notset;
    /// <summary>
    /// 获取或设置模板的可被访问范围类型
    /// </summary>
    public TemplateAccessTypes AccessType
    {
      get
      {
        if (_accessType == TemplateAccessTypes.Notset)
        {
          string value = this.ToString("AccessType", "Public");
          _accessType = value.ToEnumValue<TemplateAccessTypes>(TemplateAccessTypes.Public);
        }
        return _accessType;
      }
      set
      {
        if (value.IsNullOrEmpty())
        {
          value = TemplateAccessTypes.Notset;
        }
        this["AccessType"] = value.GetNames();
      }
    }

    private string _fullName = null;
    /// <summary>
    /// 获取完全名称，包括名称空间
    /// </summary>
    public string FullName
    {
      get
      {
        if (_fullName == null)
        {
          if (this.ParentTemplate == null)
          {
            _fullName = new List<string>() { this.DomTemplate.NameSpace, this.Name }.Join(".");
          }
          else
          {
            _fullName = new List<string>() { this.ParentTemplate.FullName, this.Name }.Join(">");
          }
        }
        return _fullName;
      }
    }

    private IContentRender _contentRender = null;
    /// <summary>
    /// 解析文本内容的处理器
    /// </summary>
    public IContentRender ContentRender
    {
      get
      {
        if (_contentRender == null)
        {
          lock (this)
          {
            if (_contentRender == null)
            {
              string patternRender = this.ToString(Consts.CONTENT_RENDER_FIELD);
              if (patternRender.IsNullOrEmpty())
              {
                _contentRender = this.ParentTemplate != null ? this.ParentTemplate.ContentRender : this.DomTemplate.ContentRender;
              }
              else
              {
                _contentRender = DomTemplateManager.GetContentRender(patternRender);
              }
            }
          }
        }
        return _contentRender;
      }
    }

    #endregion

    /// <summary>
    /// 执行Render过程
    /// </summary>
    /// <param name="paramObject"></param>
    public string DoRender(object paramObject, ITemplateRenderContext context = null)
    {
      return DoRender(this, paramObject, paramObject, context);
    }

    /// <summary>
    /// 释放资源
    /// </summary>
    public void Dispose()
    {
      if (this.ChildNodes != null)
      {
        foreach (IDisposable ele in this.ChildNodes)
        {
          ele.Dispose();
        }
        this.ChildNodes.Clear();
        this.ChildNodes = null;
      }

      if (this.ChildTemplates != null)
      {
        foreach (IDisposable tpl in this.ChildTemplates.Values)
        {
          tpl.Dispose();
        }
        this.ChildTemplates.Clear();
      }
      this.DomTemplate = null;
      this.ParentTemplate = null;
      this.ChildTemplates = null;
      _contentRender = null;
    }
  }
}
